/* 
 * Copyright 2010, 2011  Jean Champemont jean.champemont@gmail.com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of 
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "kprint.h"
#include "ports.h"
#include "globals.h"

static void addXPOS(unsigned short add) /* This function change XPOS by adding add to its value. It manages
new line if needed */
{
	if(XPOS + add >= MAXCOL)
	{
		if(YPOS + 1 >= MAXROW)
			YPOS = 0; /* TODO : Manage video memory pages when screen is full */
		else
		{
			YPOS++;
			XPOS = 0;
		}
	}
	else
		XPOS += add;
}

static void move_cursor_to(int row, int col) /* This function move the cursor to described place */
{
	unsigned short position=(row*80)+col;
	volatile unsigned short *basePort = (volatile unsigned short*)0x463; /* Reading base port from BIOS data area */ 
	outb(*basePort, 0x0F);
	outb(*basePort+1, (unsigned char)(position&0xFF));
	outb(*basePort, 0x0E);
	outb(*basePort+1, (unsigned char)((position>>8)&0xFF));       
}

static void kputchar(char c) /* This function print char to screen */
{
	volatile char *video=(volatile char*)(0xB8000+2*(YPOS*80+XPOS)); /*Computing where to write char */
	switch(c)
	{
		case '\n': /* If we have to print new line */
			YPOS++;
			XPOS=0;
		break;
		default:
			if(c != ' ' || XPOS != 0) /* This test just ensure we are not printing
									space at beginning of a line because it looks strange */
			{
				*video = c;
				addXPOS(1);
			}
		break;
	}
}

void kclear()
{
	volatile char *video=(volatile char*)0xB8000;
	unsigned char page,row,col;
	/* Just go through all pages and all row and all col */
	for(page=0;page<8;page++)
	{
		for(row=0;row<25;row++)
		{
			for(col=0;col<80;col++)
			{
				*video=0; /* Display no character here */
				video++;
				*video=0b00000111; /* Color grey on black */
				video++;
			}
		}
	}
	XPOS = 0; /* Set XPOS and YPOS to 0 */
	YPOS = 0;
	move_cursor_to(0,0);
}

void kprint(char* string)
{
	while(*string != '\0')
	{
		kputchar(*string);
		string++;
	}
	move_cursor_to(YPOS,XPOS); /* For performance reasons we only update cursor position at end of string printing */
}

void kprintui(unsigned int c)
{
	char s[10] = {0}; /* This array contains digit we have to print in reverse order */
	unsigned int div = c/10;
	unsigned int remain = c%10;
	int i = 0;
	char nPrinted = 0;
	do				/* Here, we just use the fact that :		*/
	{				/* 1234 = 123*10 + 4				*/
		s[i] = remain;		/* 123 = 12*10 + 3				*/
		i++;			/* 12 = 1*10 + 2				*/
		remain = div%10;	/* 1 = 0*10 + 1					*/
		div = div/10;		/* The digits to print are modulo 		*/
	}while(remain != 0);		/* printed in reverse order.			*/
	for(i=9;i>=0;i--)		/* So let's just browse array in reserve order 	*/
	{
		if(s[i] != 0 || nPrinted != 0 || i == 1)					/* We don't print the '0' digit except if we already printed	*/
		{										/* another non zero digit, or if the number to print is 0.	*/
			kputchar(s[i]+'0'); /* And print each digit			*/
			nPrinted++;
		}
	}
	move_cursor_to(YPOS,XPOS);
}

void kprinti(int c)
{
	char s[11] = {0}; /* This array contains digit we have to print in reverse order */
	char sign = (c<0?-1:1); /* Getting the sign of c */
	int div = (c/10)*sign;
	int remain = (c*sign)%10;
	int i = 0;
	char nPrinted = 0;
	if(sign == -1)
	{
		s[3] = '-';
	}
	do				/* Here, we just use the fact that :		*/
	{				/* 1234 = 123*10 + 4				*/
		s[i] = remain;		/* 123 = 12*10 + 3				*/
		i++;			/* 12 = 1*10 + 2				*/
		remain = div%10;	/* 1 = 0*10 + 1					*/
		div = div/10;		/* The digits to print are modulo 		*/
	}while(remain != 0);		/* printed in reverse order.			*/
	for(i=10;i>=0;i--)			/* So let's just browse array in reserve order 	*/
	{
		if(s[i] == '-')
		{
			kputchar(s[i]);
		}
		else if(s[i] != 0 || nPrinted != 0 || i == 1)					/* We don't print the '0' digit except if we already printed	*/
		{										/* another non zero digit, or if the number to print is 0.	*/
			kputchar(s[i]+'0'); /* And print each digit			*/
			nPrinted++;
		}
	}
	move_cursor_to(YPOS,XPOS);
}
